#include "SceneLoader.h"

#include <GL\glui.h>
#include <math.h>
#include <iostream>
#include <vector>

using namespace std;

#define DIMX 500
#define DIMY 500
#define INITIALPOS_X 200
#define INITIALPOS_Y 200

RGBpixmap pixmap;

float xy_aspect;
int lightNumber,lastView,wireframe,freeView,atten;
int lastChangedLight = 0;

float view_rotate[16] =	{ 1,0,0,0,
						  0,1,0,0,
						  0,0,1,0,
						  0,0,0,1 };

float obj_pos[] = { 0.0, 0.0, 0.0 };

double axis_radius_begin =  0.2;
double axis_radius_end   =  0.0;
double axis_lenght       = 16.0;
int axis_nslices = 8;
int axis_nstacks = 1;

float mat1_specular[] = {0.4, 0.4, 0.4, 1.0};	
float mat1_diffuse[] =  {0.6, 0.6, 0.6, 1.0};	
float mat1_ambient[] =  {0.6, 0.6, 0.6, 1.0};
float mat1_emission[] = {0.0,0.0,0.0,1.0};
float mat1_shininess[] = {128.0}; 

int main_window;
GLUI  *glui2;
SceneLoader * scene2;

void AxisMat() 
{
	glMaterialfv(GL_FRONT, GL_SHININESS, mat1_shininess);
	glMaterialfv(GL_FRONT, GL_SPECULAR,  mat1_specular);
	glMaterialfv(GL_FRONT, GL_DIFFUSE,   mat1_diffuse);
	glMaterialfv(GL_FRONT, GL_AMBIENT,   mat1_ambient);
	glMaterialfv(GL_FRONT, GL_EMISSION,  mat1_emission);

}

void drawAxis() 
{	
	if(scene2->getSceneInfo()->getLenght()){

		AxisMat();

		glEnable(GL_COLOR_MATERIAL);

		GLUquadric * glQ = gluNewQuadric();

		glColor3f(1.0,0.0,0.0);		
		glPushMatrix();
		glRotated(90.0, 0.0,1.0,0.0 );
		gluCylinder(glQ, axis_radius_begin, axis_radius_end,
			scene2->getSceneInfo()->getLenght(), axis_nslices, axis_nstacks);  
		glPopMatrix();
		
		glColor3f(0.0,1.0,0.0);		
		glPushMatrix();
		glRotated(-90.0, 1.0,0.0,0.0 );
		gluCylinder(glQ, axis_radius_begin, axis_radius_end,
			scene2->getSceneInfo()->getLenght(), axis_nslices, axis_nstacks);   
		glPopMatrix();

		glColor3f(0.0,0.0,1.0);		
		glPushMatrix();
		gluCylinder(glQ, axis_radius_begin, axis_radius_end,
			scene2->getSceneInfo()->getLenght(), axis_nslices, axis_nstacks);   
		glPopMatrix();

		glDisable(GL_COLOR_MATERIAL);
	}
}

void display(void)
{
	if(freeView){
		
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glMatrixMode( GL_PROJECTION );
		glLoadIdentity();
		glFrustum( -xy_aspect*.04, xy_aspect*.04, -.04, .04, .1, 500.0 );
		glMatrixMode( GL_MODELVIEW );
		glLoadIdentity();
		glTranslatef( obj_pos[0], obj_pos[1], -obj_pos[2]-40 );
		glMultMatrixf( view_rotate );
	}
	else
		scene2->CurrentViewAct();
		
	scene2->cycleLights();
	scene2->cycleComponents();
	
	drawAxis();
	
	glutSwapBuffers();
   
	glFlush();
}

void processMouse(int button, int state, int x, int y)
{
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{	 
	}
	if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
	{	
	}
	
	glutPostRedisplay();
	
}

void processMouseMoved(int x, int y)
{
	glutPostRedisplay();				
}

void processPassiveMouseMoved(int x, int y)
{
	glutPostRedisplay();				
}

void reshape(int w, int h)
{
	int tx, ty, tw, th;

	GLUI_Master.get_viewport_area( &tx, &ty, &tw, &th );
	glViewport( tx, ty, tw, th );
	xy_aspect = (float)tw / (float)th;

	glutPostRedisplay();
}

void keyboard(unsigned char key, int x, int y)
{
	scene2->changeMatByKey(key);

	switch (key) {
      case 27:		// tecla de escape termina o programa
         exit(0);
         break;
   }
}

void myGlutIdle( void )
{
  if ( glutGetWindow() != main_window ) 
    glutSetWindow(main_window);  


  glutPostRedisplay();
}

void inicializacao()
{

	glFrontFace(GL_CCW);		
	glDepthFunc(GL_LEQUAL);		
	glEnable(GL_DEPTH_TEST);	
	glEnable(GL_CULL_FACE);		
	glCullFace(GL_BACK);		

	glEnable(GL_NORMALIZE);
	glEnable(GL_LIGHTING);

	glShadeModel(GL_SMOOTH);				

	glPolygonMode(GL_FRONT, GL_FILL);	
}

void lightChangeParse(int d){
	scene2->getLightByIndex(d).second->switchState();
}

void viewChangeParse(int d){
	scene2->setCurrentViewIDbyIndex(lastView);
}

void wireframeCB(int d){
	if(wireframe)
		glPolygonMode(GL_FRONT, GL_LINE );
	else
		glPolygonMode(GL_FRONT, GL_FILL);
}

void attenCB(int d){
	
	scene2->getLightAttenuation(atten);	
}

int main(int argc, char* argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowSize (DIMX, DIMY);
	glutInitWindowPosition (INITIALPOS_X, INITIALPOS_Y);
	main_window = glutCreateWindow (argv[0]);
 
	glutDisplayFunc(display);
	GLUI_Master.set_glutReshapeFunc(reshape);
	GLUI_Master.set_glutKeyboardFunc (keyboard);
	GLUI_Master.set_glutMouseFunc(processMouse);
	glutMotionFunc(processMouseMoved);
	glutPassiveMotionFunc(processPassiveMouseMoved);   
	GLUI_Master.set_glutSpecialFunc( NULL );
   
	/* We register the idle callback with GLUI, not with GLUT */
	GLUI_Master.set_glutIdleFunc( myGlutIdle );
   
	inicializacao();

	
	if(argc==2)
		scene2 = new SceneLoader(argv[1]);
	else
		scene2 = new SceneLoader("demo.xml");

	if(!scene2->init()){
		printf("\n\n");
		system("pause");
		exit(1);
	}

	/*** Create the bottom subwindow ***/
	glui2 = GLUI_Master.create_glui_subwindow( main_window, GLUI_SUBWINDOW_BOTTOM );
	glui2->set_main_gfx_window( main_window );

	GLUI_Rotation *view_rot = glui2->add_rotation( "Rotation", view_rotate );
	view_rot->set_spin( 1.0 );
	glui2->add_column( false );

	GLUI_Translation *trans_z = 
	glui2->add_translation( "Zoom", GLUI_TRANSLATION_Z, &obj_pos[2] );
	trans_z->set_speed( .02 );
	glui2->add_column( false );
	

	GLUI_Panel *panel = glui2->add_panel( "Lights" );
	for(int i=0; i<scene2->getNumberOfLights(); ++i){
		if(i==4) glui2->add_column_to_panel(panel, false );		
		GLUI_Checkbox *check = glui2->add_checkbox_to_panel(panel,(char *)(scene2->getLightByIndex(i).first).c_str(),&lastChangedLight,i,lightChangeParse);
		check->set_int_val(scene2->getLightByIndex(i).second->isEnabled());		
	}
	glui2->add_column( false );		

	GLUI_Listbox *listbox = glui2->add_listbox("Views",&lastView,-1,viewChangeParse);

	for(int i=0; i<scene2->getNumberOfViews(); ++i){
		listbox->add_item(i,(char *)(scene2->getViewByIndex(i).first.c_str()));
	}

	glui2->add_checkbox("Wireframe",&wireframe,1,wireframeCB);
	glui2->add_checkbox("FreeView",&freeView,-1,NULL);


	GLUI_RadioGroup *radioGroup = glui2->add_radiogroup(&atten,-1,attenCB);
	glui2->add_radiobutton_to_group(radioGroup,"L. Constant attenuation");
	glui2->add_radiobutton_to_group(radioGroup,"L. Linear attenuation");
	radioGroup->set_int_val(1);

	glutMainLoop();	
	return 0;
}
